/*
 * Copyright 2009 Prime Technology.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.primefaces.facestrace.phase.listener;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.primefaces.facestrace.utils.TraceUtils;

public class TraceResourcePhaseListener implements PhaseListener {

	public final static String CSS_RESOURCE_PATTERN = "facestrace_resources:url:";
	
	public void afterPhase(PhaseEvent event) {
		if(event.getFacesContext().getExternalContext().getRequestParameterMap().containsKey("facestraceResource"))
			serveResource(event);
	}

	private void serveResource(PhaseEvent event) {
		FacesContext facesContext = event.getFacesContext();
		Map<String,String> params = facesContext.getExternalContext().getRequestParameterMap();
		String resourceName = params.get("facestraceResource");
		String resourceType = TraceUtils.getResourceFileExtension(resourceName);
		String mimeType = TraceUtils.getContentType(resourceType);
		
		int indice, tempIndice;
		byte tempArr[];
		byte mainArr[] = new byte[0];
		byte byteArr[] = new byte[65535];
		
		HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
		HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();

		try {
			String resourcePath = "/META-INF/" + resourceName;
			InputStream inputStream = this.getClass().getResourceAsStream(resourcePath);
			
			response.setContentType(mimeType);
			response.setStatus(200);
			
			if(mimeType.equals("text/css")) {
				handleCSSLoading(request, response, inputStream);
			} else {
	            ServletOutputStream outputStream = response.getOutputStream();
	            
				for (indice = 0; (indice = inputStream.read(byteArr)) > 0;) {
					tempIndice = mainArr.length + indice;
					tempArr = new byte[tempIndice];
					System.arraycopy(mainArr, 0, tempArr, 0, mainArr.length);
					System.arraycopy(byteArr, 0, tempArr, mainArr.length, indice);
					mainArr = tempArr;
				}

				outputStream.write(mainArr);
				outputStream.flush();
				outputStream.close();
			}
			
			 facesContext.responseComplete();		//Stop the jsf lifecycle
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}
	
	private void handleCSSLoading(HttpServletRequest request, HttpServletResponse response, InputStream inputStream) throws UnsupportedEncodingException, IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
		OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream(), response.getCharacterEncoding());
		String line = null;
		
		while (null != (line = reader.readLine())) {
			String parsedLine = replaceRelativeUrl(request.getContextPath(), line);
			writer.write(parsedLine+"\n");
        }
		
		writer.flush();
		writer.close();
	}

	public String replaceRelativeUrl(String contextPath, String input) {
        String actionURL = TraceUtils.getActionURL(FacesContext.getCurrentInstance()) + "?facestraceResource=";
        
        Pattern pattern = Pattern.compile(CSS_RESOURCE_PATTERN);

        Matcher matcher = pattern.matcher(input);
        return matcher.replaceAll(actionURL);
	}

	public void beforePhase(PhaseEvent event) {
		//Do nothing here
	}

	public PhaseId getPhaseId() {
		return PhaseId.RESTORE_VIEW;
	}
}